package com.learning.spring.ioc.life;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * ClassName: LifeCycleInApplicationContext
 * Description: ApplicationContext 中 bean 的生命周期
 * Date: 2018/8/3 11:01 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class LifeCycleInApplicationContext {

    public static void main(String[] args) {
        test2();
    }

    /**
     * 概述：
     * 1. Bean 在 ApplicationContext，bean 实现了 ApplicationContextAware 接口，可以设置 setApplicationContext 。
     * 2. 增加了工厂后置接口 BeanFactoryPostProcessor，在上下文容器装载配置文件之后、初始化Bean 实例之前，
     * 将处理 BeanFactoryPostProcessor 对配置信息进行加工。Spring 提供了多个工厂后置器如 CustomEditorConfigurer、PropertyPlaceholderConfigurer、CustomAutowireConfigurer等.
     * 后置工厂是容器级别的，仅仅在上下文初始化时候调用一次。
     * 3.ApplicationContext 会利用反射自动识别出配置文件中定义的BeanFactoryPostProcessor、BeanPostProcessor、InstantiationAwareBeanPostProcessorAdapter
     * 并自动将他们注册到应用上下文（需要在配置中配置）；BeanFactory 需要手动注册（addBeanPostProcessor()）
     */
    static void test() {
    }


    /**
     * ApplicationContext 中 bean 的生命周期
     *
     * ApplicationContext 在启动的时候，将首先为配置文件中的每一个<bean> 生成一个 BeanDefinition 对象
     * 当配置文件中的所有 <bean> 都被解析成 BeanDefinition 时，ApplicationContext 将调用工厂后置方法。
     */
    static void test2() {

        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        System.out.println("~~~~~~~~~ ApplicationContext 容器初始化 完成~~~~~~~~~~~");

        System.out.println("~~~~~~~~~ 开始从 ApplicationContext 容器中获取 Bean~~~~~~~~~~~");
        // 从容器中获取 Bean
        LifeCycleBean lifeCycleBean = context.getBean("lifeCycleBean", LifeCycleBean.class);
        lifeCycleBean.setName("Sam life Cycle Bean");

        LifeCycleBean lifeCycleBean1 = context.getBean("lifeCycleBean", LifeCycleBean.class);
        System.out.println(" 两次获取的Bean 对象是否为用一个： " + (lifeCycleBean == lifeCycleBean1));

        // 关闭容器
        ((ClassPathXmlApplicationContext) context).close();

        /*
            调用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法
            调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法
            调用 LifeCycleBean 构造函数
            调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法
            调用 InstantiationAwareBeanPostProcessor.postProcessPropertyValues() 方法
            调用 BeanNameAware.setBeanName() 方法
            调用 BeanFactoryAware.setBeanFactory() 方法
            调用 ApplicationContextAware.setApplicationContext() 方法
            调用 BeanPostProcessor.postProcessBeforeInitialization() 方法
            调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法
            调用 InitializingBean.afterPropertiesSet() 方法
            init-method 指定的初始化方法
            调用 BeanPostProcessor.postProcessAfterInitialization() 方法
            调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法
            ~~~~~~~~~ ApplicationContext 容器初始化 完成~~~~~~~~~~~
            ~~~~~~~~~ 开始从 ApplicationContext 容器中获取 Bean~~~~~~~~~~~
            设置 setName 属性
            两次获取的Bean 对象是否为用一个： true
            调用 DisposableBean.destroy() 方法
            destroy-method 指定的销毁方法
        */
    }


}
